
package com.wasu.sdk_ott.utils;


import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


public class MethodUtils {
    /** Only log warning about accessibility work around once */
    private static boolean loggedAccessibleWarning = false;

    private MethodUtils() {
	}
    
    public static Method getAccessibleMethod(Method method) {

        // Make sure we have a method to check
        if (method == null) {
            return (null);
        }

        // If the requested method is not public we cannot call it
        if (!Modifier.isPublic(method.getModifiers())) {
            return (null);
        }

        // If the declaring class is public, we are done
        Class<?> clazz = method.getDeclaringClass();
        if (Modifier.isPublic(clazz.getModifiers())) {
            return (method);
        }

        // Check the implemented interfaces and subinterfaces
        method =
                getAccessibleMethodFromInterfaceNest(clazz,
                        method.getName(),
                        method.getParameterTypes());
        return (method);

    }

    private static Method getAccessibleMethodFromInterfaceNest
            (Class<?> clazz, String methodName, Class<?> parameterTypes[]) {

        Method method = null;

        // Search up the superclass chain
        for (; clazz != null; clazz = clazz.getSuperclass()) {

            // Check the implemented interfaces of the parent class
            Class<?> interfaces[] = clazz.getInterfaces();
            for (int i = 0; i < interfaces.length; i++) {

                // Is this interface public?
                if (!Modifier.isPublic(interfaces[i].getModifiers()))
                    continue;

                // Does the method exist on this interface?
                try {
                    method = interfaces[i].getDeclaredMethod(methodName,
                            parameterTypes);
                } catch (NoSuchMethodException e) {
                    ;
                }
                if (method != null)
                    break;

                // Recursively check our parent interfaces
                method =
                        getAccessibleMethodFromInterfaceNest(interfaces[i],
                                methodName,
                                parameterTypes);
                if (method != null)
                    break;
            }

        }

        // If we found a method return it
        if (method != null)
            return (method);

        // We did not find anything
        return (null);

    }

    public static Method getMatchingAccessibleMethod(
            Class<?> clazz, String methodName, Class<?>[] parameterTypes) {
        // trace logging
        
        // see if we can find the method directly
        // most of the time this works and it's much faster
        try {
            Method method = clazz.getMethod(methodName, parameterTypes);
            
            try {
                method.setAccessible(true);
                
            } catch (SecurityException se) {
                // log but continue just in case the method.invoke works anyway
                if (!loggedAccessibleWarning) {
                    loggedAccessibleWarning = true;
                }
            }
            return method;
            
        } catch (NoSuchMethodException e) { /* SWALLOW */ }
        
        // search through all methods 
        int paramSize = parameterTypes.length;
        Method[] methods = clazz.getMethods();
        for (int i = 0, size = methods.length; i < size ; i++) {
            if (methods[i].getName().equals(methodName)) {	
                // log some trace information
                                
                // compare parameters
                Class<?>[] methodsParams = methods[i].getParameterTypes();
                int methodParamSize = methodsParams.length;
                if (methodParamSize == paramSize) {          
                    boolean match = true;
                    for (int n = 0 ; n < methodParamSize; n++) {
                        
                        if (!isAssignmentCompatible(methodsParams[n], parameterTypes[n])) {
                            
                            match = false;
                            break;
                        }
                    }
                    
                    if (match) {
                        // get accessible version of method
                        Method method = getAccessibleMethod(methods[i]);
                        if (method != null) {
                            try {
                                method.setAccessible(true);
                                
                            } catch (SecurityException se) {
                                // log but continue just in case the method.invoke works anyway
                                if (!loggedAccessibleWarning) {
                                    loggedAccessibleWarning = true;
                                }
                            }
                            return method;
                        }
                        
                    }
                }
            }
        }
        
        // didn't find a match
        return null;                                        
    }

    protected static final boolean isAssignmentCompatible(Class<?> parameterType, Class<?> parameterization) {
        // try plain assignment
        if (parameterType.isAssignableFrom(parameterization)) {
            return true;
        }
        
        if (parameterType.isPrimitive()) {
            // does anyone know a better strategy than comparing names?
            // also, this method does *not* do widening - you must specify exactly
            // is this the right behaviour?
            if (boolean.class.equals(parameterType)) {
                return Boolean.class.equals(parameterization);
            }         
            if (float.class.equals(parameterType)) {
                return Float.class.equals(parameterization);
            }     
            if (long.class.equals(parameterType)) {
                return Long.class.equals(parameterization);
            }     
            if (int.class.equals(parameterType)) {
                return Integer.class.equals(parameterization);
            }                
            if (double.class.equals(parameterType)) {
                return Double.class.equals(parameterization);
            }               
        }
        
        return false;
    }

    /**
     * 获取md5
     * @param s s
     * @return md5加密的串
     */
    public static String getMD5(String s) {
        MessageDigest messageDigest = null;
        try {
            messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(s.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        byte[] byteArray = messageDigest.digest();
        StringBuilder md5StrBuff = new StringBuilder();
        for (int i = 0; i < byteArray.length; i++) {
            if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {
                md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
            } else {
                md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
            }
        }
        return md5StrBuff.toString();
    }
}
